home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World's Largest Collection of Windows Software
/
The World's Largest Collection of Windows Software - Disc 1.iso
/
connect
/
_j2
/
wvnsc926
/
wvgroup.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-09-21
|
54KB
|
1,820 lines
/********************************************************************
* *
* MODULE : WVGROUP.C *
* *
* PURPOSE : This file contains the window procedure for the *
* Group viewing window for WinVN. *
* *
* FUNCTIONS : *
* WinVnViewWndProc() - Window Procedure for any *
* of WinVN's group windows *
* *
* FileLength() - Find the size in bytes of *
* a file *
* *
* ViewArticle() - Requests and views an *
* article from the server *
* *
* setArticleFocus() - Makes an article active *
* *
* UnlinkArtsInGroup() - Prepares article window *
* for deletion *
* *
* UpdateSeenArts() - Save seen info in document *
* *
* CursorToTextLine() - Locates text in a document *
* based on cursor position *
* *
* search_headers() - Search all headers for a *
* given substring *
* *
* string_compare_insensitive() - Compare two strings while *
* ignoring case sensitivity *
* *
* AffectSelected() - Set selected flag based on *
* search criteria *
* *
********************************************************************/
/*
* $Id: wvgroup.c 1.49 1994/09/18 22:49:02 jcooper Exp $
*
*/
#include <windows.h>
#include <windowsx.h> // for GlobalFreePtr (JSC)
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop
void setArticleFocus(HWND hWndArt);
long NewCursorToTextLine (int X, int Y, TypDoc * DocPtr);
long search_headers (TypDoc * HeaderDoc, header_p headers, long artindex, long num_headers);
void SaveSelectedArts (HWND hwnd, TypDoc *Doc, header_p headers, long num_headers);
long AffectSelected (TypDoc *Doc, BOOL value, BOOL compare);
char_p string_compare_insensitive (char_p a, LPSTR b);
void InitiateReceiveArticle (TypDoc *Doc, char far *articleId);
BOOL article_operation (TypDoc * Doc,
long artindex,
BOOL (*art_fun) (header_p headers,
TypGroup * group,
long artindex));
BOOL toggle_read_unread (header_p headers, TypGroup * group, long artindex);
BOOL toggle_selected (header_p headers, TypGroup * group, long artindex);
BOOL selected_true (header_p headers, TypGroup * group, long artindex);
BOOL selected_false (header_p headers, TypGroup * group, long artindex);
BOOL seen_true (header_p headers, TypGroup * group, long artindex);
BOOL seen_false (header_p headers, TypGroup * group, long artindex);
BOOL mark_read_to_here (header_p headers, TypGroup * group, long artindex);
BOOL mark_read_all (header_p headers, TypGroup * group, long artindex);
void CloseGroupWnd(HWND hWnd, TypDoc *ThisDoc);
void SetGroupMenus (HWND hWnd, int enable);
void SetMenusForMultiArticleOperation (HWND hWnd, int enable);
/*--- FUNCTION: WinVnViewWndProc --------------------------------------------
*
* Window procedure for a Group window, which contains the subjects
* of the various articles in a newsgroup.
* Note that there may be several different Group windows active;
* this routine gets called any time anything happens to any of them.
*/
long FAR PASCAL
WinVnViewWndProc (hWnd, message, wParam, lParam)
HWND hWnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
PAINTSTRUCT ps; /* paint structure */
HDC hDC; /* handle to display context */
RECT clientRect; /* selection rectangle */
TypDoc *ThisDoc;
int ih, j;
long artindex;
BOOL found;
long found_artindex;
int CtrlState;
TypBlock far *BlockPtr;
HANDLE hBlock;
unsigned int Offset;
BOOL continueFind;
char mybuf[MAXINTERNALLINE];
TypLineID MyLineID;
POINT ptCursor;
TypLine far * LinePtr;
int X, Y;
int OldSel = FALSE;
/* We know what *window* is being acted on, but we must find
* out which *document* is being acted on. There's a one-to-one
* relationship between the two, and we find out which document
* corresponds to this window by scanning the GroupDocs array.
*/
for (ih = 0, found = FALSE; !found && ih < MAXGROUPWNDS; ih++)
{
if (GroupDocs[ih].hDocWnd == hWnd)
{
found = TRUE;
ThisDoc = &(GroupDocs[ih]);
}
}
if (!found)
{
ThisDoc = CommDoc;
}
switch (message)
{
case WM_CREATE:
SetGroupMenus(hWnd, DISABLE);
NumGroupWnds++;
break;
case WM_ACTIVATE:
if (wParam)
{
ActiveGroupDoc = ThisDoc;
}
/* fall through */
case WM_SYSCOMMAND:
return (DefWindowProc (hWnd, message, wParam, lParam));
/* case WM_INITMENUPOPUP: // (JSC) now handled by SetGroupMenus
EnableMenuItem(GetMenu(hWnd),IDM_MAIL,MailCtrl.enableMail) ;
break;
*/
case WM_SIZE:
GetClientRect (hWnd, &clientRect);
ThisDoc->ScXWidth = clientRect.right;
ThisDoc->ScYHeight = clientRect.bottom;
ThisDoc->ScYLines = (clientRect.bottom - clientRect.top - TopSpace) / LineHeight;
ThisDoc->ScXChars = (clientRect.right - clientRect.left - SideSpace) / CharWidth;
break;
case WM_CLOSE:
CloseGroupWnd(hWnd, ThisDoc);
break;
case WM_DESTROY:
/* Unlink all the article windows that belong to this group */
NumGroupWnds--;
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset,
ThisDoc->ParentLineID, &BlockPtr, &LinePtr);
{
/* Clear the pointer in the line for this group in the */
/* NetDoc document. This pointer currently points */
/* to the current document, which we are wiping out */
/* with the destruction of this window. */
TypGroup far *group =
(TypGroup far *) (((char far *) LinePtr) + sizeof (TypLine));
long int CN_Total_Lines;
group->SubjDoc = (TypDoc *) NULL;
ThisDoc->InUse = FALSE;
if (ThisDoc == CommDoc)
{
CN_Total_Lines = CommDoc->TotalLines;
CommBusy = FALSE;
CommDoc = (TypDoc *) NULL;
}
/* SMR 940420 cause of mysterious F3 bug */
else {
CN_Total_Lines = group->total_headers;
}
/*CN if (group->total_headers != 0) { */
if (CN_Total_Lines != 0) { /* CN */
UpdateSeenArts (ThisDoc);
UnlinkArtsInGroup (ThisDoc);
if (group->header_handle)
free_headers (group->header_handle, group->thread_handle);
group->header_handle = (HANDLE) NULL;
group->thread_handle = (HANDLE) NULL;
group->total_headers = 0;
}
}
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
/* Clear document */
FreeDoc (ThisDoc);
/* If there's another group window, make it the active */
/* group window so we don't create a new one if the */
/* New Group flag is FALSE. */
for (j = MAXGROUPWNDS - 1; j >= 0; j--)
{
if (GroupDocs[j].InUse)
{
ActiveGroupDoc = &(GroupDocs[j]);
break;
}
}
break;
case WM_KEYDOWN:
/* See if this key should be mapped to a scrolling event
* for which we have programmed the mouse. If so,
* construct the appropriate mouse call and call the mouse code.
*/
if (wParam == VK_F6)
{
NextWindow (ThisDoc);
}
else
{
CtrlState = GetKeyState (VK_CONTROL) < 0;
for (j = 0; j < NUMKEYS; j++)
{
if (wParam == key2scroll[j].wVirtKey &&
CtrlState == key2scroll[j].CtlState)
{
SendMessage (hWnd, key2scroll[j].iMessage,
key2scroll[j].wRequest, 0L);
break;
}
}
}
break;
case WM_CHAR:
/* Carriage Return means the same as double-clicking
* on where the cursor is currently pointing.
*/
if (wParam == '\r')
{
GetCursorPos (&ptCursor);
ScreenToClient (hWnd, &ptCursor);
X = ptCursor.x;
Y = ptCursor.y;
goto getarticle;
}
else
{
}
break;
case WM_RBUTTONDBLCLK:
/* double right click will mark all up to here as read */
X = LOWORD (lParam);
Y = HIWORD (lParam);
artindex = NewCursorToTextLine (X, Y, ThisDoc);
if (artindex > -1 )
{
article_operation (ThisDoc, artindex, mark_read_to_here);
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
}
break;
case WM_MBUTTONDOWN:
/* Single middle click will toggle the read/unread status of the */
/* article */
DragMouseAction = DRAG_NONE;
if (!Initializing)
{
BOOL status;
X = LOWORD (lParam);
Y = HIWORD (lParam);
artindex = NewCursorToTextLine (X, Y, ThisDoc);
if (artindex > -1 )
{
status = article_operation (ThisDoc, artindex, toggle_read_unread);
DragMouseAction = status ? SEEN_SELECT : SEEN_DESELECT;
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
SetCapture(hWnd); // release capture on button up
}
}
break;
case WM_LBUTTONDOWN:
/* Clicking the left button on an article name toggles the
* selected/not selected status of that group.
* Currently selected groups are displayed in reverse video.
*/
DragMouseAction = DRAG_NONE;
if (!Initializing)
{
BOOL status;
X = LOWORD (lParam);
Y = HIWORD (lParam);
artindex = NewCursorToTextLine (X, Y, ThisDoc);
if (artindex > -1 )
{
if (MK_SHIFT & wParam)
{
status = article_operation(ThisDoc,artindex,toggle_read_unread);
DragMouseAction = status ? SEEN_SELECT : SEEN_DESELECT;
}
else
{
status = article_operation(ThisDoc, artindex,toggle_selected);
DragMouseAction = status ? DRAG_SELECT : DRAG_DESELECT;
}
SetCapture(hWnd); // release capture on button up
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
}
}
break;
case WM_LBUTTONUP:
/* Letting up on the left button on an article name
* gets us out of Dragging mode */
ReleaseCapture();
DragMouseAction = DRAG_NONE;
break;
case WM_MBUTTONUP:
/* Letting up on the middle button on an article name
* gets us out of Dragging mode */
ReleaseCapture();
DragMouseAction = DRAG_NONE;
break;
case WM_LBUTTONDBLCLK:
/* Double-clicking on an article subject creates an "Article"
* window, whose purpose is to display the article.
*/
X = LOWORD (lParam);
Y = HIWORD (lParam);
getarticle:;
artindex = NewCursorToTextLine (X, Y, ThisDoc);
if (artindex > -1 )
{
article_operation (ThisDoc, artindex, selected_false);
ViewArticle (ThisDoc, artindex, NO_REUSE, SHOW, NO_ID);
}
break;
case WM_MOUSEMOVE:
/* Code to drag the mouse and change the select/not selected
* status of that group.
*/
if ((!Initializing) && (DragMouseAction != DRAG_NONE))
{
X = LOWORD (lParam);
Y = HIWORD (lParam);
artindex = NewCursorToTextLine (X, Y, ThisDoc);
if (artindex > -1 )
{
switch (DragMouseAction)
{
case DRAG_SELECT:
article_operation (ThisDoc, artindex, selected_true);
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
break;
case DRAG_DESELECT:
article_operation (ThisDoc, artindex, selected_false);
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
break;
case SEEN_SELECT:
article_operation (ThisDoc, artindex, seen_true);
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
break;
case SEEN_DESELECT:
article_operation (ThisDoc, artindex, seen_false);
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
break;
}
}
}
break;
case WM_VSCROLL:
NewScrollIt (ThisDoc, wParam, lParam);
break;
case WM_HSCROLL:
HScrollIt (ThisDoc, wParam, lParam);
break;
case WM_PAINT:
{
HANDLE hBlock;
SIZE sz;
int MyLen;
unsigned int Offset;
int VertLines, HorzChars;
int EndofDoc = FALSE;
int RangeHigh, CurPos;
int indicatorwidth, Xtext;
char indicator;
unsigned int artindex;
long int artnum;
TypBlock far *NetBlockPtr;
TypLine far *NetLinePtr;
TypGroup far *group;
header_p headers;
header_p header;
HANDLE header_handle;
HANDLE thread_handle;
char scratch_line [MAXINTERNALLINE];
char date_string [80];
unsigned long OldHighestSeen;
COLORREF MyColors[4], MyBack[4];
RECT aRect;
int MyColorMask = 0, PrevColorMask = MyColorMask;
/* MyColors and MyBack are arrays of colors used to display text
* foreground and background.
* The ColorMask variables are indices into these arrays.
* We set and clear bits in these indices depending upon
* whether the article has been selected or seen.
*/
#define SEEN_MASK 1
#define SELECT_MASK 2
hDC = BeginPaint (hWnd, &ps);
GetClientRect (hWnd, &clientRect);
SelectObject (hDC, hListFont);
VertLines = ( (ThisDoc->ScYLines > (ThisDoc->TotalLines - ThisDoc->TopLineOrd))
? (ThisDoc->TotalLines - ThisDoc->TopLineOrd )
: ThisDoc->ScYLines);
HorzChars = ThisDoc->ScXChars;
MyColors[0] = ArticleUnSeenColor; // unseen/unselected
MyColors[1] = ArticleSeenColor; // seen/unselected
MyColors[2] = ListBackgroundColor; // unseen/selected
MyColors[3] = MyColors[1]; // seen/selected
MyBack[0] = MyColors[2];
MyBack[1] = MyColors[2];
if (ListBackgroundColor == RGB(0,0,0))
MyBack[2] = RGB(200,200,200); // selected = soft/white background
else
MyBack[2] = RGB(0,0,0); // selected = black background
MyBack[3] = MyBack[2];
SetTextColor (hDC, MyColors[MyColorMask]);
SetBkColor (hDC, MyBack[MyColorMask]);
/* Update the scroll bar thumb position. */
CurPos = ThisDoc->TopLineOrd;
if (CurPos < 0)
CurPos = 0;
RangeHigh = ThisDoc->TotalLines - VertLines;
if (RangeHigh < 0)
RangeHigh = 0;
SetScrollRange (hWnd, SB_VERT, 0, RangeHigh, FALSE);
SetScrollPos (hWnd, SB_VERT, CurPos, TRUE);
RangeHigh = ThisDoc->LongestLine - ThisDoc->ScXChars;
if (RangeHigh < 0)
{
RangeHigh = 0;
ThisDoc->ScXOffset = 0;
}
SetScrollRange (hWnd, SB_HORZ, 0, RangeHigh, FALSE);
SetScrollPos (hWnd, SB_HORZ, ThisDoc->ScXOffset, TRUE);
GetTextExtentPoint(hDC, "s 99999 ", 8, &sz);
indicatorwidth = sz.cx;
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset, ThisDoc->ParentLineID,
&NetBlockPtr, &NetLinePtr);
group = (TypGroup far *) ((char far *) NetLinePtr + sizeof (TypLine));
header_handle = group->header_handle;
thread_handle = group->thread_handle;
if (header_handle)
headers = lock_headers (header_handle,thread_handle);
OldHighestSeen = group->HighestPrevSeen;
UnlockLine (NetBlockPtr, NetLinePtr, &hBlock, &Offset, &MyLineID);
/* Now paint this stuff on the screen. */
X = SideSpace - ThisDoc->ScXOffset * (CharWidth+2);
Xtext = X + indicatorwidth;
Y = StartPen;
artindex = ThisDoc->TopLineOrd;
if (ThisDoc->TotalLines)
do
{
header = header_elt (headers, artindex);
artnum = header->number;
indicator = ' ';
if(header->Seen) {
indicator = 's';
} else if(OldHighestSeen) {
if(header->number > OldHighestSeen) {
indicator = 'n';
}
}
if(ThisDoc->FindOffset == artindex)
indicator = '>';
sprintf (scratch_line, "%c%5Flu %-5.5Fs %-18.18Fs %4Fd %-*s%-Fs ",
indicator,
header->number,
StringDate(date_string,header->date),
header->from,
header->lines,
header->thread_depth * 2,
"",
/* ack! */
(ThreadFullSubject || !(header->thread_depth))
? header->subject
: "\020"
);
MyLen = lstrlen (scratch_line);
/* Figure out the color of this line. */
MyColorMask = 0;
if (header->Seen)
{
MyColorMask |= SEEN_MASK;
}
else
{
MyColorMask &= (0xff - SEEN_MASK);
}
if (header->Selected)
{
MyColorMask |= SELECT_MASK;
}
else
{
MyColorMask &= 0xff - SELECT_MASK;
}
if (MyColorMask != PrevColorMask)
{
SetTextColor (hDC, MyColors[MyColorMask]);
SetBkColor (hDC, MyBack[MyColorMask]);
PrevColorMask = MyColorMask;
}
/* Now write out the line. */
SetRect (&aRect, 0, Y, clientRect.right, Y+LineHeight);
ExtTextOut (hDC, X, Y, ETO_OPAQUE|ETO_CLIPPED, &aRect,
scratch_line, MyLen, (LPINT)NULL);
Y += LineHeight;
artindex++;
}
while (--VertLines > 0 );
if (header_handle)
unlock_headers (header_handle, thread_handle);
/* We've reached the end of the data to be displayed */
/* on this window. If there's more screen real estate */
/* left, just blank it out. */
SelectObject (hDC, hListBackgroundBrush);
PatBlt (hDC, 0, Y, clientRect.right - 1, clientRect.bottom - Y, PATCOPY);
EndPaint (hWnd, &ps);
break;
}
case IDM_RETRIEVE_COMPLETE:
SetGroupMenus(hWnd, ENABLE);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDV_EXIT:
CloseGroupWnd(hWnd, ThisDoc);
break;
case IDV_NEXT:
break;
case IDM_MARK_ALL:
article_operation (ThisDoc, 0, mark_read_all);
CloseGroupWnd(hWnd, ThisDoc);
break;
case IDM_SORT_DATE:
case IDM_SORT_SUBJECT:
case IDM_SORT_LINES:
case IDM_SORT_THREADS:
case IDM_SORT_ARTNUM:
case IDM_SORT_FROM:
{ TypGroup far * group;
HANDLE header_handle,thread_handle;
header_p headers;
thread_array thread_index;
long i;
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset,
ThisDoc->ParentLineID, &BlockPtr, &LinePtr);
group = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = group->header_handle;
thread_handle = group->thread_handle;
/* this dependency on [thread_array_p][head0][head1][head2]... */
/* should be moved into headarry.c */
headers = lock_headers (header_handle,thread_handle);
thread_index = * ((thread_array_p) ((char_p) headers - sizeof (char_p)));
/* clear thread_depth info */
for (i=0;i<group->total_headers;i++)
headers[i].thread_depth = 0;
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
switch (LOWORD(wParam)) {
case IDM_SORT_DATE:
shell_sort_index_array (headers, thread_index,
ThisDoc->TotalLines, compare_date);
break;
case IDM_SORT_SUBJECT:
shell_sort_index_array (headers, thread_index,
ThisDoc->TotalLines, compare_subject);
break;
case IDM_SORT_LINES:
shell_sort_index_array (headers, thread_index,
ThisDoc->TotalLines, compare_lines);
break;
case IDM_SORT_THREADS:
if (threadp)
sort_by_threads (header_handle, thread_handle, ThisDoc->TotalLines);
else
MessageBox (hWnd, "Threading disabled", "WinVN", MB_OK);
break;
case IDM_SORT_ARTNUM:
shell_sort_index_array (headers, thread_index,
ThisDoc->TotalLines, compare_artnum);
break;
case IDM_SORT_FROM:
shell_sort_index_array (headers, thread_index,
ThisDoc->TotalLines, compare_from);
break;
}
unlock_headers (header_handle, thread_handle);
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
}
break;
case IDM_FIND:
case IDM_FIND_NEXT_SAME:
FindDoc = ThisDoc;
continueFind = TRUE;
if (!FindDoc->SearchStr[0] || LOWORD(wParam) == IDM_FIND) {
if (!(FindDoc->SearchStr[0]) && LastArticleHeaderFind[0])
strcpy(FindDoc->SearchStr, LastArticleHeaderFind);
continueFind = DialogBox (hInst, "WinVnFind", hWnd, lpfnWinVnFindDlg);
}
if (continueFind && FindDoc->SearchStr[0]) {
TypGroup far * group;
header_p headers;
HANDLE header_handle;
HANDLE thread_handle;
int starting_at;
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset, ThisDoc->ParentLineID,
&BlockPtr, &LinePtr);
group = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = group->header_handle;
thread_handle = group->thread_handle;
headers = lock_headers (header_handle,thread_handle);
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
/* 'Find Next' will start one line after */
starting_at = ThisDoc->TopLineOrd + ((LOWORD(wParam) == IDM_FIND) ? 0 : 1);
/* back up one if we're at the end */
if (starting_at >= group->total_headers)
starting_at--;
found_artindex = search_headers (ThisDoc, headers, starting_at, group->total_headers);
if (found_artindex == -1)
{
strcpy (mybuf, "\"");
strcat (mybuf, ThisDoc->SearchStr);
strcat (mybuf, "\" not found.");
MessageBox (hWnd, mybuf, "Not found", MB_OK);
}
else {
ThisDoc->TopLineOrd = (int) found_artindex;
ThisDoc->FindOffset = (int) found_artindex;
strcpy(LastArticleHeaderFind, FindDoc->SearchStr);
InvalidateRect(ThisDoc->hDocWnd,NULL,FALSE);
}
unlock_headers (header_handle,thread_handle);
}
break;
case IDM_POST:
/* We are creating the skeleton text of a new posting.
* Most of the work is done by CreatePostingWnd and
* CreatePostingText. Here we have to identify
* the newsgroup for those routines.
* Get the newsgroup from the line in NetDoc that
* points to this document.
*/
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset,
ThisDoc->ParentLineID, &BlockPtr, &LinePtr);
ExtractTextLine (ThisDoc->ParentDoc, LinePtr,
mybuf, MAXINTERNALLINE);
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
NewsgroupsPtr = mybuf;
CreatePostingWnd (hWnd, (TypDoc *) NULL, DOCTYPE_POSTING);
break;
case IDM_SAVE_SELECTED:
/* Query user for file name */
if (!DialogBox (hInst, "WinVnSaveArts", hWnd, lpfnWinVnSaveArtsDlg)) {
InvalidateRect (hWnd, NULL, TRUE);
} else {
numArtsSaved = 0;
savingArtIndex = 0;
SetMenusForMultiArticleOperation (hWnd, DISABLE);
goto doretrieve;
}
break;
case IDM_DECODE_SELECTED:
/* Query user for file name */
if (!DialogBoxParam (hInst, "WinVnDecodeArts", hWnd, lpfnWinVnDecodeArtsDlg, 1)) {
InvalidateRect (hWnd, NULL, TRUE);
} else {
if (TestCommBusy(hWnd, "Can't decode selected articles"))
break;
if (TestDecodeBusy(hWnd, "Can't decode selected articles"))
break;
DecodeInit();
CommDoc = ThisDoc;
CommDecoding = TRUE;
numArtsSaved = 0;
savingArtIndex = 0;
SetMenusForMultiArticleOperation (hWnd, DISABLE);
goto doretrieve;
}
break;
case IDM_SELECT_ALL:
/* select all articles */
AffectSelected (ThisDoc, SELECT, NO_COMPARE);
break;
case IDM_DESELECT_ALL:
/* deselect all articles */
AffectSelected (ThisDoc, DESELECT, NO_COMPARE);
break;
case IDM_SELECT_MATCH:
/* select all articles containing a string*/
FindDoc = ThisDoc;
DialogBox (hInst, "WinVnFind", hWnd, lpfnWinVnFindDlg);
if(strcmp(FindDoc->SearchStr,"")) {
if (AffectSelected (FindDoc, SELECT, COMPARE)==0) {
strcpy (mybuf, "\"");
strcat (mybuf, FindDoc->SearchStr);
strcat (mybuf, "\" not found.");
MessageBox (hWnd, mybuf, "Not found", MB_OK);
}
}
break;
case IDM_MAIL:
(MailCtrl.fnMlWinCreate)(hWnd, (TypDoc *) NULL, DOCTYPE_MAIL);
break;
case IDM_UPDATE:
if (!CommBusy) {
TypGroup far * group;
char far * group_name;
/* update the newsrc data */
UpdateSeenArts (ThisDoc);
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset,
ThisDoc->ParentLineID,&BlockPtr, &LinePtr);
group = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
group_name = (char far *) LinePtr
+ sizeof (TypLine) + sizeof (TypGroup);
// Free whatever headers are there.
if (group->header_handle)
free_headers (group->header_handle, group->thread_handle);
group->header_handle = (HANDLE) NULL;
group->thread_handle = (HANDLE) NULL;
// zero out the received line count
RcvLineCount = 0;
// capture the mouse to the usenet window, so that we keep
// the hourglass.
SetCapture (hWndConf);
SetGroupMenus(hWnd, DISABLE);
CommDoc = ThisDoc;
CommState = ST_GROUP_RESP;
strcpy (mybuf, "GROUP ");
lstrcat (mybuf, group_name);
PutCommLine (mybuf);
}
break;
}
break;
case IDM_ARTICLE_RETRIEVE_COMPLETE:
{
TypGroup far * group;
header_p headers;
HANDLE header_handle;
HANDLE thread_handle;
int justSavedIndex;
if (savingArtIndex == -1) /* this retrieve wasn't part of a save operation */
break;
if (CodingState == INACTIVE)
{
/* If this is the 1st article saved, then value of Append depends
* on what the user selected in dialog. If > 1st, always append
*/
if (!MRRWriteDocument (ActiveArticleDoc, sizeof (TypText),
SaveArtFileName,
(numArtsSaved==0)?SaveArtAppend:TRUE))
{
MessageBox (hWnd, "Could not write to file. Operation canceled", "Problems saving file", MB_OK | MB_ICONEXCLAMATION);
SetMenusForMultiArticleOperation (hWnd, ENABLE);
savingArtIndex = -1;
break;
}
} else {
if (CompleteThisDecode() == FAIL)
{
DecodeDone ();
MessageBox (hWnd, "Aborted decode", "Problems during decode", MB_OK | MB_ICONEXCLAMATION);
SetMenusForMultiArticleOperation (hWnd, ENABLE);
savingArtIndex = -1;
break;
}
}
justSavedIndex = savingArtIndex;
numArtsSaved++;
savingArtIndex++;
doretrieve:;
LockLine (ThisDoc->hParentBlock, ThisDoc->ParentOffset, ThisDoc->ParentLineID,
&BlockPtr, &LinePtr);
group = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = group->header_handle;
thread_handle = group->thread_handle;
headers = lock_headers (header_handle,thread_handle);
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
if (numArtsSaved > 0) // deselect the article just finished
(header_elt(headers, justSavedIndex))->Selected = FALSE;
/* skip to next selected article */
while (savingArtIndex < group->total_headers &&
(header_elt(headers, savingArtIndex))->Selected == FALSE)
savingArtIndex++;
if (savingArtIndex >= group->total_headers) /* done */
{
if (numArtsSaved > 0) {
if (CodingState == INACTIVE)
{
sprintf (mybuf, "Saved %d article%c to file %s",
numArtsSaved, (numArtsSaved==1)?' ':'s',SaveArtFileName);
MessageBox (hWnd, mybuf, "Done", MB_OK);
}
} else
MessageBox (hWnd, "No articles selected", "Done", MB_OK);
if (CodingState != INACTIVE)
DecodeDone();
SetMenusForMultiArticleOperation (hWnd, ENABLE);
// (JSC) now deselect article as soon as it's successfully finished
// for (savingArtIndex=0; savingArtIndex < group->total_headers; savingArtIndex++ )
// (header_elt(headers, savingArtIndex))->Selected = FALSE;
unlock_headers (header_handle,thread_handle);
savingArtIndex = -1; /* reset to non-saving state */
}
else
{
if (KeepArticleHeaderVisible)
AdjustTopScByDoc (ThisDoc, savingArtIndex);
sprintf(mybuf, "%ld", (header_elt(headers, savingArtIndex))->number);
(header_elt(headers, savingArtIndex))->Seen = TRUE;
unlock_headers (header_handle, thread_handle);
if (CodingState != INACTIVE)
{
if ((currentCoded = InitCoded(hWnd)) == NULL)
{
MessageBox (hWnd, "Unable to continue due to memory constraints. Aborted", "Init Coded Object Error", MB_OK);
DecodeDone();
SetMenusForMultiArticleOperation (hWnd, ENABLE);
savingArtIndex = -1;
break;
}
InitiateReceiveArticle (ThisDoc, mybuf);
UpdateBlockStatus (); // display some initial status
} else
ViewArticle (ThisDoc, savingArtIndex, REUSE, NO_SHOW, NO_ID);
}
InvalidateRect (hWnd, NULL, FALSE);
break;
}
default:
return (DefWindowProc (hWnd, message, wParam, lParam));
}
return (0);
}
/*------------ CloseGroupWnd ------------------------------
*
* Make sure this Wnd is not the active Comm window, then destroy it
*/
void CloseGroupWnd(HWND hWnd, TypDoc *ThisDoc)
{
if (CommBusy && ThisDoc == CommDoc)
MessageBox (hWnd,
"Please wait until group activity is complete",
"Cannot close group window", MB_OK|MB_ICONSTOP);
else
DestroyWindow (hWnd);
}
/*------------ SetGroupMenus ------------------------------
* dis/enable menu items which depend on group list being completely
* retrieved
*/
void
SetGroupMailMenu(HWND hWnd)
{
HMENU hMenu, hSubMenu;
hMenu = GetMenu (hWnd);
hSubMenu = GetSubMenu (hMenu, 0); // Articles menu
EnableMenuItem (hSubMenu, IDM_MAIL, MailCtrl.enableMail);
}
void
SetGroupMenus (HWND hWnd, int enable)
{
HMENU hMenu, hSubMenu;
UINT mode;
if (enable == ENABLE)
mode = MF_BYCOMMAND|MF_ENABLED;
else
mode = MF_BYCOMMAND|MF_DISABLED|MF_GRAYED;
hMenu = GetMenu (hWnd);
hSubMenu = GetSubMenu (hMenu, 0); // Articles menu
EnableMenuItem (hSubMenu, IDM_UPDATE, mode);
EnableMenuItem (hSubMenu, IDM_SAVE_SELECTED, mode);
EnableMenuItem (hSubMenu, IDM_DECODE_SELECTED, mode);
EnableMenuItem (hSubMenu, IDM_SELECT_ALL, mode);
EnableMenuItem (hSubMenu, IDM_DESELECT_ALL, mode);
EnableMenuItem (hSubMenu, IDM_SELECT_MATCH, mode);
EnableMenuItem (hSubMenu, IDM_MARK_ALL, mode);
EnableMenuItem (hSubMenu, IDV_EXIT, mode);
SetGroupMailMenu(hWnd);
hSubMenu = GetSubMenu (hMenu, 1); // Sort menu
EnableMenuItem (hSubMenu, IDM_SORT_DATE, mode);
EnableMenuItem (hSubMenu, IDM_SORT_SUBJECT, mode);
EnableMenuItem (hSubMenu, IDM_SORT_LINES, mode);
EnableMenuItem (hSubMenu, IDM_SORT_THREADS, mode);
EnableMenuItem (hSubMenu, IDM_SORT_ARTNUM, mode);
EnableMenuItem (hSubMenu, IDM_SORT_FROM, mode);
hSubMenu = GetSubMenu (hMenu, 2); // Search menu
EnableMenuItem (hSubMenu, IDM_FIND, mode);
EnableMenuItem (hSubMenu, IDM_FIND_NEXT_SAME, mode);
}
/*------------ SetMenusForMultiArticleOperation ----------
* (JSC) killer function name, huh?!
* During multi-article op (i.e. Save selected, Decode selected)
* we don't want the user to do any of these things
*/
void
SetMenusForMultiArticleOperation (HWND hWnd, int enable)
{
HMENU hMenu, hSubMenu;
UINT mode;
if (enable == ENABLE)
mode = MF_BYCOMMAND|MF_ENABLED;
else
mode = MF_BYCOMMAND|MF_DISABLED|MF_GRAYED;
hMenu = GetMenu (hWnd);
hSubMenu = GetSubMenu (hMenu, 0); // Articles menu
EnableMenuItem (hSubMenu, IDM_UPDATE, mode);
EnableMenuItem (hSubMenu, IDM_SAVE_SELECTED, mode);
EnableMenuItem (hSubMenu, IDM_DECODE_SELECTED, mode);
EnableMenuItem (hSubMenu, IDV_EXIT, mode);
EnableMenuItem (hSubMenu, IDM_MARK_ALL, mode);
hSubMenu = GetSubMenu (hMenu, 1); // Sort menu
EnableMenuItem (hSubMenu, IDM_SORT_DATE, mode);
EnableMenuItem (hSubMenu, IDM_SORT_SUBJECT, mode);
EnableMenuItem (hSubMenu, IDM_SORT_LINES, mode);
EnableMenuItem (hSubMenu, IDM_SORT_THREADS, mode);
EnableMenuItem (hSubMenu, IDM_SORT_ARTNUM, mode);
EnableMenuItem (hSubMenu, IDM_SORT_FROM, mode);
}
/* --- Function FileLength -------------------------------------------
*
* Find the size, in bytes, of a file.
*
* Entry hFile handle of the file in question.
*
* Exit returns the length of the file in bytes.
*
* This routine is no longer used.
*/
long
FileLength (hFile)
HFILE hFile;
{
long lCurrentPos = _llseek (hFile, 0L, 1);
long lFileLength = _llseek (hFile, 0L, 2);
_llseek (hFile, lCurrentPos, 0);
return lFileLength;
}
BOOL
article_operation (TypDoc * Doc,
long artindex,
BOOL (*art_fun) (header_p headers,
TypGroup * group,
long artindex))
{
HANDLE hBlock;
unsigned int Offset;
TypLineID MyLineID;
TypBlock far *BlockPtr;
TypLine far *LinePtr;
TypGroup * GroupDoc;
HANDLE header_handle;
HANDLE thread_handle;
BOOL result = FALSE;
header_p headers;
LockLine (Doc->hParentBlock, Doc->ParentOffset,
Doc->ParentLineID, &BlockPtr, &LinePtr);
GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = GroupDoc->header_handle;
if (header_handle) {
thread_handle = GroupDoc->thread_handle;
headers = lock_headers (header_handle,thread_handle);
result = art_fun(headers, GroupDoc, artindex);
unlock_headers (header_handle,thread_handle);
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
}
return (result);
}
BOOL
toggle_read_unread (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
/* only try if in range. All this work for these two lines 8^) */
if ((artindex > -1 ) && (artindex < GroupDoc->total_headers)) {
header_p header = header_elt (headers, artindex);
header->Seen = ( header->Seen ? FALSE : TRUE );
return (header->Seen);
}
return(FALSE);
}
BOOL
mark_read_to_here (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
header_p header;
/* only try if in range. All this work for these two lines 8^) */
if ((artindex > -1 ) && (artindex < GroupDoc->total_headers)) {
int i;
for (i = 0; i <= artindex; i++) {
header = header_elt (headers, i);
header->Seen = TRUE;
}
return(TRUE);
}
return(FALSE);
}
BOOL
mark_read_all (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
header_p header;
int i;
for (i = 0; i < GroupDoc->total_headers; i++) {
header = header_elt (headers, i);
header->Seen = TRUE;
}
return(TRUE);
}
BOOL
toggle_selected (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
/* only try if in range. All this work for these two lines 8^) */
if ((artindex > -1 ) && (artindex < GroupDoc->total_headers)) {
header_p header = header_elt (headers, artindex);
header->Selected = ( header->Selected ? FALSE : TRUE );
return(header->Selected);
}
return(FALSE);
}
BOOL
seen_false (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
/* only try if in range. */
if ((artindex > -1 ) && (artindex < GroupDoc->total_headers)) {
header_p header = header_elt (headers, artindex);
header->Seen = FALSE;
return(TRUE);
}
return(FALSE);
}
BOOL
seen_true (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
/* only try if in range. */
if ((artindex > -1 ) && (artindex < GroupDoc->total_headers)) {
header_p header = header_elt (headers, artindex);
header->Seen = TRUE;
return(TRUE);
}
return(FALSE);
}
BOOL
selected_true (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
/* only try if in range. */
if ((artindex > -1 ) && (artindex < GroupDoc->total_headers)) {
header_p header = header_elt (headers, artindex);
header->Selected = TRUE;
return(TRUE);
}
return(FALSE);
}
BOOL
selected_false (header_p headers,
TypGroup * GroupDoc,
long artindex)
{
/* only try if in range. */
if ((artindex > -1 ) && (artindex < GroupDoc->total_headers)) {
header_p header = header_elt (headers, artindex);
header->Selected = FALSE;
return(TRUE);
}
return(FALSE);
}
/*-- function ViewArticle -------------------------------------------------
*
* View a given article. Either create a new window for it or
* recycle an existing window.
* This function requests an article from the server, so there
* must not already be a transaction in progress.
* Can retrieve an article by artindex from the group header list,
* or any arbitrary article ID.
*
* Entry Doc points to the document for this group.
* artindex index into header array for this group.
* Reuse is TRUE if we ought to reuse the
* currently active article window (if any).
* showArt is TRUE to retrieve maximized (shown)
* is FALSE to retrieve minimized
* articleId is NO_ID if wish to retrieve artindex->number
* is some art ID if wish to retrieve article by ID
*/
void
ViewArticle (Doc, artindex, Reuse, showArt, articleId)
TypDoc *Doc;
long artindex;
BOOL Reuse;
BOOL showArt;
char far *articleId;
{
TypDoc *MyDoc;
TypGroup far *GroupDoc;
BOOL newdoc;
BOOL found;
int docnum;
TypBlock far *BlockPtr;
TypLine far *LinePtr;
HWND hWndArt;
int x,y,width,height;
char mybuf[MAXINTERNALLINE];
char far *lpsz;
HWND hWndGroup = Doc->hDocWnd;
HANDLE header_handle;
HANDLE thread_handle;
header_p headers;
header_p header;
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&BlockPtr, &LinePtr);
GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
if (articleId == NO_ID) /* if retrieving artindex, only try if in range */
if ((artindex < 0) || (artindex >= GroupDoc->total_headers))
return;
header_handle = GroupDoc->header_handle;
thread_handle = GroupDoc->thread_handle;
headers = lock_headers (header_handle,thread_handle);
header = header_elt(headers, artindex);
if (articleId == NO_ID && (MyDoc = header->ArtDoc))
{
/* We already have a document containing the article */
/* so just activate it. */
if (showArt)
{
setArticleFocus( MyDoc->hDocWnd );
ShowWindow(MyDoc->hDocWnd,SW_SHOWNORMAL);
} else
ShowWindow(MyDoc->hDocWnd,SW_SHOWMINIMIZED);
InvalidateRect (MyDoc->hDocWnd, NULL, FALSE);
SendMessage(hWndGroup, IDM_ARTICLE_RETRIEVE_COMPLETE, 0, 0);
goto endit;
}
if (TestCommBusy(hWndGroup, "Can't request text of article"))
goto endit;
newdoc = FALSE;
if ((NewArticleWindow && !Reuse) || !ActiveArticleDoc || !(ActiveArticleDoc->InUse))
{
found = FALSE;
for (docnum = 0; docnum < MAXARTICLEWNDS; docnum++)
{
if (!ArticleDocs[docnum].InUse)
{
found = TRUE;
newdoc = TRUE;
CommDoc = &(ArticleDocs[docnum]);
break;
}
}
if (!found)
{
MessageBox (hWndGroup,
"You have too many article windows active;\n"
"Close one or uncheck the option"
"'New Window for each Article'.",
"Can't open new window", MB_OK | MB_ICONASTERISK);
goto endit;
}
}
else
{
/* Must reuse old window for this article. */
ActiveArticleDoc->LongestLine = 0;
ActiveArticleDoc->ScXOffset = 0;
ActiveArticleDoc->TextSelected = FALSE;
EnableMenuItem(GetMenu(ActiveArticleDoc->hDocWnd),IDM_COPY,MF_GRAYED) ;
EnableMenuItem(GetMenu(ActiveArticleDoc->hDocWnd),IDM_DESELECT_ALL,MF_GRAYED) ;
CommDoc = ActiveArticleDoc;
/* sever the article/artindex connection */
if (CommDoc->ParentDoc == Doc) // (JSC) is this check really necessary?
(header_elt (headers,CommDoc->ParentOffset))->ArtDoc = (TypDoc *) NULL;
/* clear out old doc */
FreeDoc (CommDoc);
}
header->Seen = TRUE;
InvalidateRect (hWndGroup, NULL, FALSE);
if (articleId == NO_ID)
lpsz = (char far *) header->subject;
else
lpsz = articleId;
strcpy (mybuf, "Retrieving \"");
lstrcat (mybuf, lpsz);
lstrcat (mybuf, "\"");
if (newdoc)
{
char poschars[MAXINTERNALLINE];
/* Compute default screen position. */
if (xScreen > 88 * ArtCharWidth) {
width = 88 * ArtCharWidth;
} else {
width = xScreen - 1 * ArtCharWidth;
}
x = xScreen - width;
y = (int) (yScreen * 3 / 8);
height = (int) (yScreen * 5 / 8) - (1 * ArtLineHeight);
/* If the screen position has been saved, use that instead. */
GetPrivateProfileString (szAppName, "ArticleWindowPos", "!",
poschars,MAXINTERNALLINE,szAppProFile);
if(poschars[0] != '!') {
sscanf(poschars,"%d,%d,%d,%d",&x,&y,&width,&height);
}
hWndArt = CreateWindow ("WinVnArt",
mybuf,
WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
/* Initial X pos */
x - (docnum * ArtCharWidth),
/* Initial Y pos */
y + docnum * ArtLineHeight,
width, /* Initial X Width */
/* Initial Y height */
height,
NULL,
NULL,
hInst,
NULL);
if (!hWndArt)
return; /* ??? */
SetHandleBkBrush (hWndArt, hArticleBackgroundBrush);
ShowWindow (hWndArt, SW_SHOWNORMAL);
}
else
{
hWndArt = CommDoc->hDocWnd;
SetWindowText (hWndArt, mybuf);
}
/* Now that we have created the window, create the corresponding
* document, and make the new window active.
*/
InitDoc (CommDoc, hWndArt, Doc, DOCTYPE_ARTICLE);
CommDoc->InUse = TRUE;
CommDoc->LastSeenLineID = artindex; /* Keep an index with the article */
if (showArt)
{
setArticleFocus( hWndArt) ;
ShowWindow (hWndArt, SW_SHOWNORMAL);
} else
ShowWindow (hWndArt, SW_SHOWMINIMIZED);
header->ArtDoc = CommDoc;
CommDoc->ParentOffset = (int) artindex; /* should this be iff articleId==NO_ID ? */
InvalidateRect (hWndArt, NULL, FALSE);
UpdateWindow (hWndArt);
if (articleId == NO_ID)
{
sprintf(mybuf, "%ld", header->number);
InitiateReceiveArticle (Doc, mybuf);
}
else
InitiateReceiveArticle (Doc, articleId);
endit:
unlock_headers (header_handle, thread_handle);
}
void
setArticleFocus(HWND hWndArt)
{
SetArticleRot13Mode(hWndArt,FALSE) ;
SetActiveWindow (hWndArt);
SetFocus (hWndArt);
}
void
InitiateReceiveArticle (TypDoc *Doc, char far *articleId)
{
TypBlock far *BlockPtr;
TypLine far *LinePtr;
char far *lpszGroupName;
char mybuf[MAXINTERNALLINE];
HANDLE hBlock;
unsigned int Offset;
TypLineID MyLineID;
CommLinePtr = CommLineIn;
CommBusy = TRUE;
CommState = ST_ARTICLE_RESP;
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&BlockPtr, &LinePtr);
/* If we're not already in this group on the server,
* send out a GROUP command for this window so we get back
* into the right Group.
*/
lpszGroupName = (char far *) LinePtr + sizeof (TypLine) + sizeof (TypGroup);
if (lstrcmp (CurrentGroup, lpszGroupName))
{
CommState = ST_GROUP_REJOIN;
strcpy (mybuf, "GROUP ");
lstrcat (mybuf, lpszGroupName);
mylstrncpy (CurrentGroup, lpszGroupName, MAXGROUPNAME);
PutCommLine (mybuf);
}
UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
sprintf (mybuf, "ARTICLE %s", articleId);
PutCommLine (mybuf);
}
/*-- Function UnlinkArtsInGroup ---------------------------------------
*
* Modify all the article documents and all the article windows currently
* associated with a group so that none of them points to that group.
* Used when the group window is going away or is being recycled.
*
* Entry GroupDoc points to the document to which references
* should be eliminated.
*/
void
UnlinkArtsInGroup (GroupDoc)
TypDoc *GroupDoc;
{
int iart;
for (iart = 0; iart < MAXARTICLEWNDS; iart++)
{
if (ArticleDocs[iart].InUse && ArticleDocs[iart].ParentDoc == GroupDoc)
{
ArticleDocs[iart].ParentDoc = (TypDoc *) NULL;
ArticleDocs[iart].hParentBlock = 0;
}
}
}
/*--- function UpdateSeenArts -------------------------------------------
*
* Given a Group document, update the TypGroup line for
* that document in the Net document with respect to which
* articles have been seen.
* This routine would typically be called just before a Group document
* is going to be destroyed or erased. That would be the time to
* take the information in the TypArticle structures of each line
* in the document and transfer it to the line in the NetDoc document
* corresponding to this group.
*
* This routine has to take information of the form:
* 123:Unseen; 124:Seen; 125:Unseen; 126:Unseen; 127:Seen; 128:Seen; 129:Seen
* found in the TypArticle structures in consecutive lines in the document
* and transform it to the general form used by .newsrc files:
* 124,127-129
* (though we are using our internal representation & not ASCII characters).
*
* Entry Doc points to the document for this group.
*
* Exit The line in the Net document corresponding to this
* group has been updated.
*/
void
UpdateSeenArts (Doc)
TypDoc *Doc;
{
TypRange MyRange, *RangePtr;
TypGroup *group;
TypLine far * ParentLine;
TypBlock far * ParentBlock;
HANDLE hLine,header_handle,thread_handle;
TypLine *LocalLinePtr;
header_p headers;
header_p header;
BOOL InSeen = TRUE;
unsigned int MyLength;
unsigned int maxRanges;
unsigned long artindex;
/* Get the line in the Net document that corresponds to this
* group. Make a local copy of it and set RangePtr to point to
* the first range in that line. We will ignore the old line's
* "seen" data and create the information afresh from what we
* have in this document.
*/
LockLine (Doc->hParentBlock, Doc->ParentOffset, Doc->ParentLineID,
&ParentBlock, &ParentLine);
hLine = LocalAlloc (LMEM_MOVEABLE, BLOCK_SIZE);
LocalLinePtr = (TypLine *) LocalLock (hLine);
group = (TypGroup *) ((char *) LocalLinePtr + sizeof (TypLine));
MoveBytes (ParentLine, LocalLinePtr, ParentLine->length);
if (group->total_headers > 0) {
header_handle = group->header_handle;
thread_handle = group->thread_handle;
set_index_to_identity (header_handle, thread_handle, group->total_headers);
headers = lock_headers (header_handle,thread_handle);
group->nRanges = 0;
maxRanges = ((Doc->BlockSize - Doc->SplitSize) - ParentLine->length +
group->nRanges * sizeof (TypRange)) / sizeof (TypRange) - 1;
RangePtr = (TypRange *) ((char *) LocalLinePtr + sizeof (TypLine) +
RangeOffset (group->NameLen));
MyRange.First = 1;
/* Get the first line in this document.
* If it cannot be found, just set Last=First and skip the
* proceeding processing. Otherwise, assume we've seen everything
* up to but not including the first article in the document.
*/
/* LockLine (Doc->hFirstBlock, sizeof (TypBlock), 0L, &BlockPtr, &LinePtr); */
artindex = 0;
if (!Doc->TotalLines)
{
MyRange.Last = 1;
}
else
{
header = (header_elt (headers,artindex));
MyRange.Last = header->number - 1;
/* Loop to scan through the document, fabricating article ranges.
*/
do
{
header = (header_elt (headers,artindex));
if (header->Seen)
{
if (InSeen)
{
/* Continuing a sequence of seen articles. */
MyRange.Last = header->number;
}
else
{
/* Starting a new sequence of seen articles. */
MyRange.First = header->number;
MyRange.Last = header->number;
InSeen = TRUE;
}
}
else
{
if (InSeen)
{
/* Ending a sequence of seen articles. */
InSeen = FALSE;
*(RangePtr++) = MyRange;
(group->nRanges)++;
}
else
{
/* Continuing a sequence of unseen articles. */
}
}
}
while (( group->nRanges < maxRanges) &&
((++artindex < Doc->TotalLines)));
if (InSeen)
{
*(RangePtr++) = MyRange;
(group->nRanges)++;
}
}
}
unlock_headers (header_handle, thread_handle);
MyLength = sizeof (TypLine) + RangeOffset (group->NameLen) +
sizeof (TypRange) * (group->nRanges) + sizeof (int);
LocalLinePtr->length = MyLength;
*(int *) ((char *) LocalLinePtr + MyLength - sizeof (int)) = MyLength;
ReplaceLine (LocalLinePtr, &ParentBlock, &ParentLine);
GlobalUnlock (ParentBlock->hCurBlock);
LocalUnlock (hLine);
LocalFree (hLine);
}
/*-- function CursorToTextLine ----------------------------------------
*
* Routine to locate a text line in a document, based on the
* cursor position. Used to figure out which line is being selected
* when a user clicks a mouse button.
*
* Entry X, Y are the position of the cursor.
* DocPtr points to the current document.
*
* Exit *LinePtr points to the current line, if one was found.
* *BlockPtr points to the current block, if found.
* Function returns TRUE iff a line was found that corresponds
* to the cursor position.
*/
long
NewCursorToTextLine (X, Y, DocPtr)
int X;
int Y;
TypDoc *DocPtr;
{
int SelLine;
if (Y < TopSpace || (unsigned) Y > TopSpace + DocPtr->ScYLines * LineHeight ||
X < SideSpace)
{
/* Cursor is in no-man's-land at edge of window. */
return(-1);
}
else
{
SelLine = (Y - TopSpace) / LineHeight;
return ( DocPtr->TopLineOrd + SelLine);
}
}
/* this has been changed to use header_elt (SMR) */
long
search_headers (TypDoc * HeaderDoc, header_p headers,
long artindex, long num_headers)
{
char_p temp;
do {
temp = (header_elt(headers,artindex))->subject;
if (string_compare_insensitive (temp, HeaderDoc->SearchStr))
return (artindex); /* return the index */
} while (artindex++ < (num_headers - 1));
return (-1); /* not found */
}
char_p
string_compare_insensitive (char_p a, char far * b)
{
int lena = lstrlen (a);
int lenb = lstrlen (b);
int count;
for ( count = lena - lenb + 1 ; count > 0 ; count--, a++)
if (strnicmp (a,b,lenb) == 0)
return a;
return (NULL);
}
long
AffectSelected (TypDoc *Doc, BOOL value, BOOL compare)
{
TypGroup far * group;
HANDLE header_handle,thread_handle;
header_p headers;
TypBlock far *BlockPtr;
TypLine far * LinePtr;
char_p temp;
long index, num_affected;
LockLine (Doc->hParentBlock, Doc->ParentOffset,
Doc->ParentLineID, &BlockPtr, &LinePtr);
group = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
header_handle = group->header_handle;
thread_handle = group->thread_handle;
headers = lock_headers (header_handle,thread_handle);
for (index=0, num_affected=0; index < group->total_headers; index++ )
if (compare) {
temp = (header_elt(headers, index))->subject;
if (string_compare_insensitive (temp, Doc->SearchStr)) {
(header_elt(headers, index))->Selected = value;
num_affected++;
}
} else {
(header_elt(headers, index))->Selected = value;
num_affected++;
}
InvalidateRect(Doc->hDocWnd,NULL,FALSE);
return (num_affected);
}